home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 October / EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso / Aminet / mus / play / tracker_4_31.lzh / tracker / Arch / NAS / audio.c next >
C/C++ Source or Header  |  1995-03-16  |  6KB  |  299 lines

  1. /* NAS/audio.c 
  2.     vi:ts=3 sw=3:
  3.  */
  4.  
  5. /* $Id: audio.c,v 1.3 1995/03/17 00:32:02 espie Exp espie $
  6.  * $Log: audio.c,v $
  7.  * Revision 1.3  1995/03/17  00:32:02  espie
  8.  * Typos fixed.
  9.  *
  10.  * Revision 1.2  1995/03/11  23:06:18  espie
  11.  * *** empty log message ***
  12.  *
  13.  * Revision 1.1  1995/03/08  13:48:24  espie
  14.  * Initial revision
  15.  *
  16.  */
  17. /* 
  18.  
  19.     Stephen Hocking (sysseh@devetir.qld.gov.au)
  20.  
  21.     The event oriented nature of NAS programming dictated a rather unusual
  22.     solution. Because NAS is built around an event loop, it demands to be in
  23.     control of the application. We can either massively patch the tracker 
  24.     sources to allow this, or simulate co-routines with occasional snoops
  25.     on the event queue so as not to miss events. Either of these are too much
  26.     work for me.
  27.     What I then did was to use fork and have the processes squirting data down
  28.     a pipe. The back end handles all the netaudio stuff, processing events 
  29.     and requesting data from the pipe when necessary. The front end waits
  30.     until the backend returns an int saying what the max frequency is, 0 if
  31.     it fails to make a connection. Then it runs along producing data and
  32.     stuffing it down the pipe as normal.
  33. */
  34.  
  35.  
  36. #include "defs.h"
  37. #include "extern.h"
  38. #include <unistd.h>
  39. #include <fcntl.h>
  40. #include <audio/audiolib.h>
  41. #include <audio/soundlib.h>
  42.  
  43. #define DEFAULT_SET_MIX
  44. #define DEFAULT_BUFFERS
  45. #define NEW_OUTPUT_SAMPLES_AWARE
  46.  
  47. #include "Arch/common.c"
  48.  
  49. #define BUF_MAX 1024
  50.  
  51. LOCAL int audio;                       /* pipe fd to netaudio process */
  52.  
  53.  
  54. LOCAL int dsp_samplesize = 16; /* must be 8 or 16 */
  55.  
  56. /* communication with child */
  57.  
  58. LOCAL int pipe1[2], pipe2[2];
  59.  
  60. LOCAL int num_tracks = 2;
  61. LOCAL int data_format;
  62. LOCAL int sample_rate = 44100;
  63.  
  64.  
  65.  
  66.  
  67. #define BUF_SAMPLES    (2 * sample_rate)
  68. #define LOW_WATER    (BUF_SAMPLES / 3)
  69.  
  70.  
  71.  
  72. /*-------------------------------------------------------------------------*/
  73. /***
  74.  ***     Child part... This code never communicates with the rest of tracker
  75.  ***     except through pipes 
  76.  ***/
  77.  
  78. LOCAL int endian_data = 1;
  79. #define little_endian ((*(char *)(&endian_data)) == 1)
  80. typedef struct
  81.     {
  82.    AuServer *aud;
  83.    AuFlowID flow;
  84.    int fd;
  85.    char *buf;
  86.     } InfoRec, *InfoPtr;
  87.  
  88. LOCAL InfoRec infor;
  89. LOCAL char *server = NULL;
  90.  
  91. LOCAL void fatalError(char *message)
  92.     {
  93.    fprintf(stderr, message);
  94.    fprintf(stderr, "\n");
  95.    exit(1);
  96.     }
  97.  
  98. LOCAL void sendFile(AuServer *aud, InfoPtr i, AuUint32 numBytes)
  99.     {
  100.    int n;
  101.  
  102.    while (numBytes) 
  103.         {
  104.         if (n = read(i->fd, i->buf, numBytes))
  105.             {
  106.             AuWriteElement(aud, i->flow, 0, n, i->buf, AuFalse, NULL);
  107.             numBytes -= n;
  108.             }
  109.         else
  110.             exit(0);
  111.         }
  112.     }
  113.  
  114. LOCAL AuBool eventHandler(AuServer *aud, AuEvent *ev,
  115.     AuEventHandlerRec *handler)
  116.     {
  117.     InfoPtr i = (InfoPtr) handler->data;
  118.  
  119.     switch (ev->type)
  120.         {
  121.    case AuEventTypeElementNotify:
  122.       {
  123.         AuElementNotifyEvent *event = (AuElementNotifyEvent *) ev;
  124.     
  125.         switch (event->kind)
  126.             {
  127.        case AuElementNotifyKindLowWater:
  128.            sendFile(aud, i, event->num_bytes);
  129.             break;
  130.         case AuElementNotifyKindState:
  131.             switch (event->cur_state)
  132.                 {
  133.           case AuStatePause:
  134.                 if (event->reason != AuReasonUser)
  135.                 sendFile(aud, i, event->num_bytes);
  136.                 break;
  137.                 }
  138.             }
  139.       }
  140.        }
  141.     return AuTrue;
  142.     }
  143.  
  144. LOCAL int doNetAudioConn()
  145.     {
  146.       AuDeviceID device = AuNone;
  147.       AuElement  elements[3];
  148.       char *filer;
  149.       int i;
  150.   
  151.   
  152.       if (!(infor.aud = AuOpenServer(server, 0, NULL, 0, NULL, NULL))) 
  153.         {
  154.         fprintf(stderr, "Can't open audio server\n");
  155.         return 0;
  156.         }
  157.  
  158.     data_format = (little_endian) ? 
  159.         AuFormatLinearSigned16LSB : AuFormatLinearSigned16MSB;
  160.  
  161.       infor.fd = pipe1[0];
  162.  
  163.     if (sample_rate > AuServerMaxSampleRate(infor.aud))
  164.         sample_rate = AuServerMaxSampleRate(infor.aud);
  165.  
  166.     if (sample_rate < AuServerMinSampleRate(infor.aud))
  167.         sample_rate = AuServerMinSampleRate(infor.aud);
  168.  
  169.           /* look for an output device */
  170.    for (i = 0; i < AuServerNumDevices(infor.aud); i++)
  171.        if ((AuDeviceKind(AuServerDevice(infor.aud, i)) ==
  172.             AuComponentKindPhysicalOutput) &&
  173.             AuDeviceNumTracks(AuServerDevice(infor.aud, i)) == num_tracks)
  174.             {
  175.             device = AuDeviceIdentifier(AuServerDevice(infor.aud, i));
  176.             break;
  177.             }
  178.  
  179.     if (device == AuNone)
  180.         fatalError("Couldn't find an output device");
  181.  
  182.       if (!(infor.flow = AuCreateFlow(infor.aud, NULL)))
  183.        fatalError("Couldn't create flow");
  184.  
  185.       AuMakeElementImportClient(&elements[0], sample_rate, data_format, 
  186.         num_tracks, AuTrue, BUF_SAMPLES, LOW_WATER, 0, NULL);
  187.     AuMakeElementExportDevice(&elements[1], 0, device, sample_rate,
  188.        AuUnlimitedSamples, 0, NULL);
  189.     AuSetElements(infor.aud, infor.flow, AuTrue, 2, elements, NULL);
  190.  
  191.     AuRegisterEventHandler(infor.aud, AuEventHandlerIDMask, 0, infor.flow,
  192.         eventHandler, (AuPointer) &infor);
  193.  
  194.     infor.buf = (char *) malloc(BUF_SAMPLES * num_tracks *
  195.         AuSizeofFormat(data_format));
  196.  
  197.     return sample_rate;
  198.     }
  199.  
  200. LOCAL void HandleEvents()
  201.     {
  202.     AuStartFlow(infor.aud, infor.flow, NULL);
  203.     while (1)
  204.         AuHandleEvents(infor.aud);
  205.     }
  206.  
  207.  
  208. LOCAL void start_child()
  209.     {
  210.     sample_rate = doNetAudioConn();
  211.     write(pipe2[1], &sample_rate, sizeof(int));
  212.     HandleEvents();        /* Never returns */
  213.     }
  214.  
  215. /***
  216.  ***    End of child part
  217.  ***/
  218. /*-------------------------------------------------------------------------*/
  219.  
  220.  
  221.  
  222. int open_audio(f, s)
  223. int f;
  224. int s;
  225.     {
  226.       int childpid;
  227.   
  228.       stereo = s;
  229.       sample_rate = f;
  230.  
  231.       if (stereo)
  232.        num_tracks = 2;
  233.     else
  234.        num_tracks = 1;
  235.  
  236.       if (pipe(pipe1) < 0 || pipe(pipe2) < 0)
  237.         end_all("Can't create pipes");
  238.  
  239.       if ((childpid = fork()) < 0)
  240.         end_all("Can't fork");
  241.       else if (childpid > 0)      /* parent - must wait for sample rate */
  242.         {
  243.       close(pipe1[0]);
  244.       close(pipe2[1]);
  245.  
  246.       read(pipe2[0], &sample_rate, sizeof(int));  /* sample for parent */
  247.       
  248.       audio = pipe1[1];
  249.         dsize = 2;
  250.         samples_max = BUF_MAX * num_tracks;
  251.       buffer16 = (short *)malloc(samples_max * dsize);
  252.       idx = 0;
  253.  
  254.       return sample_rate;
  255.         }
  256.   else                           /* Child */
  257.           start_child();                /* never returns */
  258.     }
  259.  
  260. LOCAL void actually_flush_buffer()
  261.     {
  262.     write(audio, buffer16, dsize * idx);
  263.       idx = 0;
  264.     }
  265.  
  266. void output_samples(left, right, n)
  267. int left, right, n;
  268.     {
  269.     if (idx >= samples_max - 1)
  270.         actually_flush_buffer();
  271.     add_samples16(left, right, n);
  272.     }
  273.  
  274. void flush_buffer()
  275.     {    /* Dummy version */
  276.     }
  277.  
  278. void close_audio()
  279.     {
  280.       actually_flush_buffer();
  281.     close(audio);
  282.     free(buffer16);
  283.     }
  284.  
  285. /* dummy system calls, to patch ? */
  286. void set_synchro(s)
  287.     {
  288.     }
  289.  
  290. int update_frequency()
  291.     {
  292.       return 0;
  293.     }
  294.  
  295. void discard_buffer()
  296.     {
  297.     }
  298.  
  299.